package com.atguigu.test06;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @author haoranlu
 * @project IntelliJ IDEA
 */
public abstract class BasicDAOImp1<T> {
    //type代表T的实际类型
    private Class<T> type;
    //在创建子类对象时一定会调用父类的默认构造
    public BasicDAOImp1(){
        //这个this是你正在new的对象
        //那么这个clazz就是正在new的对象的那个子类的类型的Class对象，即this.Getclass()代表的当前子类EmployeeDAOImp1这个对象
        Class<? extends BasicDAOImp1> clazz = this.getClass();
        //通过子类对象获取泛型父类的对象
        Type t = clazz.getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;  //强转是为了调用getActualTypeArguments()调用实际的参数
        Type[] types = pt.getActualTypeArguments();
        type = (Class)types[0];
    }

    public int update(String sql,Object... args) throws Exception {
        Connection conn = JDBCToolsV3.getConnection();
        PreparedStatement pst = conn.prepareStatement(sql);
        if (args!=null & args.length>0){
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i]);
            }
        }
        int len = pst.executeUpdate();
        pst.close();
        //JDBCToolsV3.free(conn);//故意不管，考虑到线程在多个位置可能共享同一个连接对象
        return len;
    }
    public T getBean(String sql,Object... args) throws Exception{
        Connection conn = JDBCToolsV3.getConnection();
        PreparedStatement pst = conn.prepareStatement(sql);
        if (args!=null && args.length>0){
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i]);
            }
        }
        //第一步,创建T的对象
        T t =  type.newInstance();
        ResultSet rs = pst.executeQuery();
        /**
         * 结果集的元数据的对象，（元数据：描述数据的数据，描述结果集中的数据的数据）
         * 例如：结果集记录的列数
         *      结果集字段名等
         * */
        ResultSetMetaData metaData = rs.getMetaData();
        int counts = metaData.getColumnCount();
        if (rs.next()) {
            //为T对象的属性赋值
            //有几列，说明有几个属性
            for (int i = 0; i < counts; i++) {
                //Field field = type.getDeclaredField(metaData.getColumnName(i+1));
                Field field = type.getDeclaredField(metaData.getColumnLabel(i+1));
                //(metaData.getColumnName(i+1)这个是数据库中的列的字段名，我们要获取的时Javabean当中的属性名
                //在sql语句中，用别名来代表属性名
                field.setAccessible(true);
                field.set(t,rs.getObject(i+1));
            }
        }
        rs.close();
        pst.close();
        return t;
    }
    public List<T> getBeanList(String sql, Object... args) throws Exception{
        Connection conn = JDBCToolsV3.getConnection();
        PreparedStatement pst = conn.prepareStatement(sql);
        if (args!=null && args.length>0){
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i]);
            }
        }
        //第一步,创建T的对象
        ArrayList<T> list = new ArrayList<T>();
        ResultSet rs = pst.executeQuery();
        /**
         * 结果集的元数据的对象，（元数据：描述数据的数据，描述结果集中的数据的数据）
         * 例如：结果集记录的列数
         *      结果集字段名等
         * */
        ResultSetMetaData metaData = rs.getMetaData();
        int counts = metaData.getColumnCount();
        while (rs.next()) {
            T t =  type.newInstance();
            //为T对象的属性赋值
            //有几列，说明有几个属性
            for (int i = 0; i < counts; i++) {
                Field field = type.getDeclaredField(metaData.getColumnName(i+1));
                field.setAccessible(true);
                field.set(t,rs.getObject(i+1));
            }
            list.add(t);
        }
        rs.close();
        pst.close();
        return list;
    }
}
